﻿using Microsoft.SharePoint.Client;
using System;
using System.Collections.Generic;
using System.Linq;

namespace Sources
{
	/// <summary>
	/// Deploy the Artefacts to SharePoint
	/// </summary>
	public static class EnsureData
	{
		/// <summary>
		/// Deploy Fields to SharePoint
		/// </summary>
		/// <param name="context">SharePoint context</param>
		/// <param name="field">Fields to deploy</param>
		/// <returns>The SharePoint field instances</returns>
		public static Field EnsureField(ClientContext context, FieldArtefact field)
		{
			Field returnField = null;

			var web = field.ToRootWeb ? context.Site.RootWeb : context.Web;

			context.Load(web.Fields, fields => fields.Include(fld => fld.InternalName, fld => fld.SchemaXml));
			context.ExecuteQuery();

			foreach (var fld in web.Fields)
			{
				if (string.Equals(fld.InternalName, field.Name, StringComparison.CurrentCultureIgnoreCase))
				{
					returnField = fld;
					break;
				}
			}

			if (returnField == null)
			{
				var xml = field.GetXml();
				returnField = web.Fields.AddFieldAsXml(xml, false, AddFieldOptions.DefaultValue);
				web.Update();
				context.Load(returnField, fld => fld.InternalName);
				context.ExecuteQuery();
			}

			if (field.Type != FieldTypeEnum.Lookup &&
				field.Type != FieldTypeEnum.LookupMulti)
			{
				return returnField;
			}

			if (string.IsNullOrEmpty(field.FieldRef) ||
				string.IsNullOrEmpty(field.ListName))
			{
				return returnField;
			}

			BindingManager.BindLookup(context, field, returnField);

			return returnField;
		}
		
		/// <summary>
		/// Deploy ContentTypes to SharePoint
		/// </summary>
		/// <param name="context">SharePoint context</param>
		/// <param name="contentType">ContentTypes to deploy</param>
		/// <returns>The SharePoint ContentType instances</returns>
		public static ContentType EnsureContentType(ClientContext context, ContentTypeArtefact contentType)
		{
			ContentType returnContentType = null;
			var fields = new List<Field>();

			foreach (FieldArtefact fi in contentType.FieldItems)
			{
				fields.Add(EnsureField(context, fi));
			}

			context.Load(context.Web.ContentTypes, contentTypes => contentTypes.Include(ct => ct.Name, ct => ct.FieldLinks));
			context.ExecuteQuery();

			foreach (var ct in context.Web.ContentTypes)
			{
				if (string.Equals(ct.Name, contentType.Name, StringComparison.CurrentCultureIgnoreCase))
				{
					returnContentType = ct;
					break;
				}
			}
			
			if (returnContentType == null)
			{
				var creationInfo = new ContentTypeCreationInformation
				{
					Id = contentType.ID,
					Name = contentType.Name,
					Description = contentType.Description,
					Group = contentType.Group
				};
				returnContentType = context.Web.ContentTypes.Add(creationInfo);
				context.Web.Update();
				context.Load(returnContentType, ct => ct.Name);
				context.ExecuteQuery();

				foreach (var fld in fields)
				{
					var link = new FieldLinkCreationInformation
					{
						Field = fld
					};
					returnContentType.FieldLinks.Add(link);
					returnContentType.Update(true);
					context.ExecuteQuery();

				}
			}

			return returnContentType;
		}

		/// <summary>
		/// Deploy Lists to SharePoint
		/// </summary>
		/// <param name="context">SharePoint context</param>
		/// <param name="list">Lists to deploy</param>
		/// <returns>The SharePoint List instances</returns>
		public static List EnsureList(ClientContext context, ListArtefact list)
		{
			List returnList = null;

			context.Load(context.Web.Lists, lists => lists.Include(l => l.Title, l => l.ContentTypes));
			context.ExecuteQuery();

			foreach (var l in context.Web.Lists)
			{
				if (string.Equals(l.Title, list.Title, StringComparison.CurrentCultureIgnoreCase))
				{
					returnList = l;
					break;
				}
			}

			if (returnList == null)
			{
				var listParams = new ListCreationInformation
				{
					Title = list.Title,
					Description = list.Description
				};
				listParams.TemplateType = (int) (list.ListTemplateType ?? ListTemplateTypeEnum.GenericList);
				returnList = context.Web.Lists.Add(listParams);

				context.ExecuteQuery();

				if (list.ContentTypes != null)
				{
					foreach (var ct in list.ContentTypes)
					{
						var contentType = EnsureContentType(context, ct);

						returnList.ContentTypes.AddExistingContentType(contentType);
					}


					context.Load(returnList.ContentTypes, contentTypes => contentTypes.Include(c => c.Name));
					context.ExecuteQuery();

					if (list.RemoveOtherContentTypes)
					{
						for (var i = returnList.ContentTypes.Count - 1; i >= 0; i--)
						{
							if (list.ContentTypes.All(ct => ct.Name != returnList.ContentTypes[i].Name))
							{
								returnList.ContentTypes[i].DeleteObject();
							}
						}

						context.ExecuteQuery();
					}
				}
			}
			
			return returnList;
		}
	}
}
